package com.paydemo.pay.RabbitMQ;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.RetryPolicy;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

import java.util.HashMap;
import java.util.Map;

/**
 * RabbitMQ 配置类
 */
@Configuration
public class RabbitMQConfig {

    /**
     * 交换机 - 持久化
     */
    @Bean
    public DirectExchange paymentExchange() {
        return ExchangeBuilder.directExchange(MqConstants.PAYMENT_EXCHANGE)
                .durable(true) // 持久化
                .build();
    }
    
    /**
     * 死信交换机
     */
    @Bean
    public DirectExchange deadLetterExchange() {
        return ExchangeBuilder.directExchange(MqConstants.DEAD_LETTER_EXCHANGE)
                .durable(true) // 持久化
                .build();
    }

    /**
     * 支付订单创建队列 - 持久化、设置死信队列
     */
    @Bean
    public Queue orderCreateQueue() {
        Map<String, Object> args = new HashMap<>();
        // 设置死信交换机
        args.put("x-dead-letter-exchange", MqConstants.DEAD_LETTER_EXCHANGE);
        // 设置死信路由键
        args.put("x-dead-letter-routing-key", MqConstants.DEAD_LETTER_ORDER_CREATE_KEY);
        
        return QueueBuilder.durable(MqConstants.PAYMENT_ORDER_CREATE_QUEUE)
                .withArguments(args)
                .build();
    }

    /**
     * 支付成功队列 - 持久化、设置死信队列
     */
    @Bean
    public Queue paymentSuccessQueue() {
        Map<String, Object> args = new HashMap<>();
        // 设置死信交换机
        args.put("x-dead-letter-exchange", MqConstants.DEAD_LETTER_EXCHANGE);
        // 设置死信路由键
        args.put("x-dead-letter-routing-key", MqConstants.DEAD_LETTER_SUCCESS_KEY);
        
        return QueueBuilder.durable(MqConstants.PAYMENT_SUCCESS_QUEUE)
                .withArguments(args)
                .build();
    }

    /**
     * 支付失败队列 - 持久化、设置死信队列
     */
    @Bean
    public Queue paymentFailQueue() {
        Map<String, Object> args = new HashMap<>();
        // 设置死信交换机
        args.put("x-dead-letter-exchange", MqConstants.DEAD_LETTER_EXCHANGE);
        // 设置死信路由键
        args.put("x-dead-letter-routing-key", MqConstants.DEAD_LETTER_FAIL_KEY);
        
        return QueueBuilder.durable(MqConstants.PAYMENT_FAIL_QUEUE)
                .withArguments(args)
                .build();
    }

    /**
     * 支付超时队列 - 持久化、设置死信队列
     */
    @Bean
    public Queue paymentTimeoutQueue() {
        Map<String, Object> args = new HashMap<>();
        // 设置死信交换机
        args.put("x-dead-letter-exchange", MqConstants.DEAD_LETTER_EXCHANGE);
        // 设置死信路由键
        args.put("x-dead-letter-routing-key", MqConstants.DEAD_LETTER_TIMEOUT_KEY);
        
        return QueueBuilder.durable(MqConstants.PAYMENT_TIMEOUT_QUEUE)
                .withArguments(args)
                .build();
    }
    
    /**
     * 死信队列 - 订单创建
     */
    @Bean
    public Queue deadLetterOrderCreateQueue() {
        return QueueBuilder.durable(MqConstants.DEAD_LETTER_ORDER_CREATE_QUEUE).build();
    }
    
    /**
     * 死信队列 - 支付成功
     */
    @Bean
    public Queue deadLetterSuccessQueue() {
        return QueueBuilder.durable(MqConstants.DEAD_LETTER_SUCCESS_QUEUE).build();
    }
    
    /**
     * 死信队列 - 支付失败
     */
    @Bean
    public Queue deadLetterFailQueue() {
        return QueueBuilder.durable(MqConstants.DEAD_LETTER_FAIL_QUEUE).build();
    }
    
    /**
     * 死信队列 - 支付超时
     */
    @Bean
    public Queue deadLetterTimeoutQueue() {
        return QueueBuilder.durable(MqConstants.DEAD_LETTER_TIMEOUT_QUEUE).build();
    }

    /**
     * 支付订单创建队列绑定关系
     */
    @Bean
    public Binding orderCreateBinding() {
        return BindingBuilder.bind(orderCreateQueue())
                .to(paymentExchange())
                .with(MqConstants.PAYMENT_ORDER_CREATE_KEY);
    }

    /**
     * 支付成功队列绑定关系
     */
    @Bean
    public Binding paymentSuccessBinding() {
        return BindingBuilder.bind(paymentSuccessQueue())
                .to(paymentExchange())
                .with(MqConstants.PAYMENT_SUCCESS_KEY);
    }

    /**
     * 支付失败队列绑定关系
     */
    @Bean
    public Binding paymentFailBinding() {
        return BindingBuilder.bind(paymentFailQueue())
                .to(paymentExchange())
                .with(MqConstants.PAYMENT_FAIL_KEY);
    }

    /**
     * 支付超时队列绑定关系
     */
    @Bean
    public Binding paymentTimeoutBinding() {
        return BindingBuilder.bind(paymentTimeoutQueue())
                .to(paymentExchange())
                .with(MqConstants.PAYMENT_TIMEOUT_KEY);
    }
    
    /**
     * 死信队列绑定关系 - 订单创建
     */
    @Bean
    public Binding deadLetterOrderCreateBinding() {
        return BindingBuilder.bind(deadLetterOrderCreateQueue())
                .to(deadLetterExchange())
                .with(MqConstants.DEAD_LETTER_ORDER_CREATE_KEY);
    }
    
    /**
     * 死信队列绑定关系 - 支付成功
     */
    @Bean
    public Binding deadLetterSuccessBinding() {
        return BindingBuilder.bind(deadLetterSuccessQueue())
                .to(deadLetterExchange())
                .with(MqConstants.DEAD_LETTER_SUCCESS_KEY);
    }
    
    /**
     * 死信队列绑定关系 - 支付失败
     */
    @Bean
    public Binding deadLetterFailBinding() {
        return BindingBuilder.bind(deadLetterFailQueue())
                .to(deadLetterExchange())
                .with(MqConstants.DEAD_LETTER_FAIL_KEY);
    }
    
    /**
     * 死信队列绑定关系 - 支付超时
     */
    @Bean
    public Binding deadLetterTimeoutBinding() {
        return BindingBuilder.bind(deadLetterTimeoutQueue())
                .to(deadLetterExchange())
                .with(MqConstants.DEAD_LETTER_TIMEOUT_KEY);
    }

    /**
     * 消息转换器
     */
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }
    
    /**
     * 重试模板
     */
    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();
        
        // 重试策略: 最大重试次数3次
        RetryPolicy retryPolicy = new SimpleRetryPolicy(3);
        retryTemplate.setRetryPolicy(retryPolicy);
        
        // 重试间隔策略: 指数退避策略
        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        backOffPolicy.setInitialInterval(1000); // 初始间隔1秒
        backOffPolicy.setMultiplier(2.0);       // 倍数
        backOffPolicy.setMaxInterval(10000);    // 最大间隔10秒
        retryTemplate.setBackOffPolicy(backOffPolicy);
        
        return retryTemplate;
    }
    
    /**
     * 配置消息恢复策略，使用重新发布恢复器，将消息发布到死信队列
     */
    @Bean
    public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate) {
        return new RepublishMessageRecoverer(rabbitTemplate, MqConstants.DEAD_LETTER_EXCHANGE, "");
    }
    
    /**
     * 自定义RabbitTemplate，配置消息发送确认回调
     */
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(messageConverter);
        
        // 消息发送到Exchange的回调
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (!ack) {
                System.err.println("消息发送到Exchange失败: " + cause);
            }
        });
        
        // 消息从Exchange路由到Queue失败的回调
        rabbitTemplate.setReturnsCallback(returned -> {
            System.err.println("消息路由到Queue失败: exchange=" + returned.getExchange() + 
                   ", routingKey=" + returned.getRoutingKey() + 
                   ", replyCode=" + returned.getReplyCode() + 
                   ", replyText=" + returned.getReplyText());
        });
        
        return rabbitTemplate;
    }
} 